package com.sitech.openapi.componet;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.*;
import com.sitech.openapi.componet.ObjectTree;
import com.sitech.openapi.componet.ObjectTree.TreeNode;

import java.util.*;

public class MapBean extends ObjectTree{

    private final Log logger = LogFactory.getLog(this.getClass());

    public MapBean() {
    }

    public MapBean(String rkey, TreeNode cnode) {
        super(rkey, cnode);
    }

    public MapBean append(MapBean bean) throws RuntimeException {
        LinkedHashMap<String, Object> map = this.node.Iterator;
        if (map.isEmpty()) {
            super.node = bean.getNode();
            return this;
        } else {
            Iterator i$ = map.entrySet().iterator();

            while(i$.hasNext()) {
                Map.Entry<String, Object> e = (Map.Entry)i$.next();
                this.setMapBeanByPath((String)e.getKey(), bean);
            }

            return this;
        }
    }

    public boolean hasChildren(String key) {
        LinkedHashMap<String, Object> map = super.node.Iterator;
        Iterator i$ = map.entrySet().iterator();

        while(true) {
            Map.Entry e;
            do {
                if (!i$.hasNext()) {
                    return false;
                }

                e = (Map.Entry)i$.next();
                if (e.getValue() instanceof TreeNode) {
                    TreeNode children = (TreeNode)e.getValue();
                    Map p = children.Iterator;
                    if (p.containsKey(key)) {
                        return true;
                    }
                }
            } while(!(e.getValue() instanceof List));

            List list = (List)e.getValue();
            if (list.size() == 0) {
                return false;
            }

            for(int i = 0; i < list.size(); ++i) {
                if (list.get(i) instanceof TreeNode) {
                    TreeNode n = (TreeNode)list.get(i);
                    Map a = n.Iterator;
                    if (a.containsKey(key)) {
                        return true;
                    }
                }
            }
        }
    }

    public void setValueAndAttr(String key, Object value, String... attrStrs) {
        super.setValueAndAttr(0, key, value, attrStrs);
    }

    public void setValue(String key, Object value) {
        super.setValueAndAttr(1, key, value, new String[0]);
    }

    public TreeNode getNode(String key) {
        return super.getNode(key);
    }

    public List<TreeNode> getNodeAll(String key) {
        return super.getNodeAll(key);
    }

    public Object getValue(String key) {
        TreeNode cnode = super.getNode(key);
        return cnode == null ? null : cnode.getNodeValue();
    }

    public void setAttr(String key, String... attrStrs) {
        super.setValueAndAttr(2, key, "", attrStrs);
    }

    public Map<String, String> getAttr(String key) {
        TreeNode cnode = super.getNode(key);
        return cnode == null ? null : cnode.getNodeAttr();
    }

    public String toXML() {
        ObjTreeCaseXml objTreeCaseXml = new ObjTreeCaseXml(super.node);
        return objTreeCaseXml.toXML();
    }

    /**
     * MapBean部分内容转XML
     * @param key 抽象路径
     */
    public String toXML(String key) {
        if (key == null || ("").equals(key)) {
            return "";
        }
        TreeNode cnode = super.getNode(key);
        if (cnode == null || ("").equals(cnode)) {
            return "";
        }

        String[] keys = key.split("\\.");
        int len = keys.length;
        int pos = keys[(len - 1)].indexOf("[");
        String rkey = null;
        if (pos != -1) {
            rkey = keys[(len - 1)].substring(0, pos);
        } else {
            rkey = keys[(len - 1)];
        }

        LinkedHashMap<String, Object> iterator = new LinkedHashMap<String, Object>();
        iterator.put(rkey, cnode);
        TreeNode fnode = new TreeNode();
        fnode.setIterator(iterator);

        ObjTreeCaseXml objTreeCaseXml = new ObjTreeCaseXml(fnode);
        return objTreeCaseXml.toXML();
    }

    /**
     * 将符合属性要求的XML节点转为MapBean
     * @param xml 报文
     * @param attrStrs 属性组
     * @return List MapBean返参
     */
    public List<MapBean> fromXMLByAttr(String xml, String... attrStrs) {

        List<MapBean> list = new ArrayList<MapBean>();
        List<org.dom4j.Element> node_list = new ArrayList<org.dom4j.Element>();

        try {
            Document doc = DocumentHelper.parseText(xml);
            Element root = doc.getRootElement(); // 得到XML 的根节点

            // 处理根节点
            Map<String, String> root_attr_map = this.getElemAttr(root);
            boolean is_exist = this.isAdapterAttr(root_attr_map, attrStrs); // attrStrs是否和 某个节点 的
            // 属性适配
            if (is_exist == true) {
                TreeNode cnode = new TreeNode();
                if (root.isTextOnly()) {
                    cnode.setNodeAttr((LinkedHashMap<String, String>) root_attr_map);
                    cnode.setNodeValue(root.getTextTrim());
                    // System.out.println(new MapBean(root.getName(), cnode).toXML());
                    list.add(new MapBean(root.getName(), cnode));
                } else {
                    this.traverseDOM(root, cnode.getIterator());
                    cnode.setNodeAttr((LinkedHashMap<String, String>) root_attr_map);
                    // System.out.println(new MapBean(root.getName(), cnode).toXML());
                    list.add(new MapBean(root.getName(), cnode));
                }
            }

            // 处理后续节点
            this.treeWalkFindAttr(root, node_list, attrStrs);

            for (int i = 0; i < node_list.size(); i++) {

                Element elem = node_list.get(i);

                TreeNode cnode = new TreeNode();
                if (elem.isTextOnly()) {
                    cnode.setNodeValue(elem.getTextTrim());
                    cnode.setNodeAttr((LinkedHashMap<String, String>) this.getElemAttr(elem));
                    // System.out.println(new MapBean(elem.getName(), cnode).toXML());
                    list.add(new MapBean(elem.getName(), cnode));
                } else {
                    this.traverseDOM(elem, cnode.getIterator());
                    cnode.setNodeAttr((LinkedHashMap<String, String>) this.getElemAttr(elem));
                    // System.out.println(new MapBean(elem.getName(), cnode).toXML());
                    list.add(new MapBean(elem.getName(), cnode));

                }
            }

        } catch (DocumentException e) {
            e.printStackTrace();
        }

        return list;
    }

    private void treeWalkFindAttr(Element element, List<Element> node_list, String... attrStrs) throws DocumentException {
        int i = 0;

        for(int size = element.nodeCount(); i < size; ++i) {
            Node dom4j_node = element.node(i);
            if (dom4j_node instanceof Element) {
                Map<String, String> attr_map = this.getElemAttr((Element)dom4j_node);
                boolean is_exist = this.isAdapterAttr(attr_map, attrStrs);
                if (is_exist) {
                    node_list.add((Element)dom4j_node);
                }

                this.treeWalkFindAttr((Element)dom4j_node, node_list, attrStrs);
            }
        }

    }

    /**
     * xml报文转MapBean
     * @param xml 报文
     */
    public void fromXML(String xml) {
        try {
            Map p_map = super.node.getIterator();
            Document doc = DocumentHelper.parseText(xml.trim());
            Element root = doc.getRootElement(); // 得到XML 的根节点
            String rootName = root.getName();

            Map<String, String> root_attr = this.getElemAttr(root);

            TreeNode rootNode = null;
            if (root.isTextOnly()) {
                rootNode = new TreeNode();
                rootNode.setNodeValue(root.getTextTrim());
                rootNode.setNodeAttr((LinkedHashMap<String, String>) root_attr);
                this.putValue(p_map, rootName, rootNode);
            } else {
                rootNode = new TreeNode();
                rootNode.setNodeAttr((LinkedHashMap<String, String>) root_attr);
                this.putValue(p_map, rootName, rootNode);
                p_map = ((TreeNode) p_map.get(rootName)).getIterator();
                this.traverseDOM(root, p_map);
            }

        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }

    /**
     * 递归解析XML
     * @param element DOM节点
     * @param p_map MapBean迭代指针
     */
    @SuppressWarnings("rawtypes")
    private void traverseDOM(Element element, Map p_map) {
        for (Iterator it = element.elementIterator(); it.hasNext();) {
            Element elem = (Element) it.next();

            String elem_name = elem.getName();

            Map<String, String> attr_map = this.getElemAttr(elem);

            if (elem.isTextOnly()) {
                TreeNode cnode = new TreeNode();
                cnode.setNodeValue(elem.getTextTrim());
                cnode.setNodeAttr((LinkedHashMap<String, String>) attr_map);
                this.putValue(p_map, elem_name, cnode);
            } else {
                TreeNode cnode = new TreeNode();
                cnode.setNodeAttr((LinkedHashMap<String, String>) attr_map);
                this.putValue(p_map, elem_name, cnode);

                Map c_p_map = null;
                if (p_map.get(elem_name) instanceof List) {
                    List c_p_list = (List) p_map.get(elem_name);
                    c_p_map = ((TreeNode) c_p_list.get(c_p_list.size() - 1)).getIterator();
                } else {
                    c_p_map = ((TreeNode) p_map.get(elem_name)).getIterator();
                }
                traverseDOM(elem, c_p_map);
            }
        }
    }

    private Map<String, String> getElemAttr(Element elem) {
        Map<String, String> attr_map = new LinkedHashMap();
        Iterator it = elem.attributeIterator();

        while(it.hasNext()) {
            Attribute attr = (Attribute)it.next();
            attr_map.put(attr.getName(), attr.getValue());
        }

        return attr_map;
    }

    private void putValue(Map p_map, String key, Object value) {
        Object obj = p_map.get(key);
        if (obj == null) {
            p_map.put(key, value);
        } else if (obj instanceof List) {
            ((List)obj).add(value);
        } else {
            List list = new ArrayList();
            list.add(obj);
            list.add(value);
            p_map.put(key, list);
        }

    }

    private TreeNode getMapNodeInner(TreeNode mn, int inner) {
        TreeNode nMapNode = null;
        if (inner == 0) {
            return mn;
        } else {
            Map<String, Object> map = mn.getIterator();
            Iterator it = map.keySet().iterator();
            String nKey = (String)it.next();
            nMapNode = (TreeNode)map.get(nKey);
            if (nMapNode.getIterator().size() > 1) {
                throw new RuntimeException("systemException");
            } else {
                --inner;
                return this.getMapNodeInner(nMapNode, inner);
            }
        }
    }

    public MapBean getMapBeanByPathInner(String key, int inner) {
        if (key != null && !"".equals(key)) {
            if (inner == 0) {
                return this.getMapBeanByPath(key);
            } else {
                TreeNode cnode = super.getNode(key);
                TreeNode innerMapNode = this.getMapNodeInner(cnode, inner - 1);
                Map<String, Object> rMap = innerMapNode.getIterator();
                Iterator it = rMap.keySet().iterator();
                if (!it.hasNext()) {
                    return new MapBean();
                } else {
                    String rKey = (String)it.next();
                    TreeNode rNode = (TreeNode)rMap.get(rKey);
                    return new MapBean(rKey, rNode);
                }
            }
        } else {
            return null;
        }
    }

    public MapBean getMapBeanByPath(String key) {
        if (key != null && !"".equals(key)) {
            TreeNode cnode = super.getNode(key);
            if (cnode != null && !"".equals(cnode)) {
                String[] keys = key.split("\\.");
                int len = keys.length;
                int pos = keys[len - 1].indexOf("[");
                String rkey = null;
                if (pos != -1) {
                    rkey = keys[len - 1].substring(0, pos);
                } else {
                    rkey = keys[len - 1];
                }

                return new MapBean(rkey, cnode);
            } else {
                return null;
            }
        } else {
            return null;
        }
    }

    public List<MapBean> getMapBeanByPathAll(String key) {
        if (key != null && !"".equals(key)) {
            List<TreeNode> node_list = super.getNodeAll(key);
            String[] keys = key.split("\\.");
            int len = keys.length;
            int pos = keys[len - 1].indexOf("[");
            String rkey = null;
            if (pos != -1) {
                rkey = keys[len - 1].substring(0, pos);
            } else {
                rkey = keys[len - 1];
            }

            List<MapBean> mb_list = new ArrayList();
            Iterator i$ = node_list.iterator();

            while(i$.hasNext()) {
                TreeNode node = (TreeNode)i$.next();
                mb_list.add(new MapBean(rkey, node));
            }

            return mb_list;
        } else {
            return null;
        }
    }

    /**
     * 根据抽象路径设置MapBean
     * @param key 抽象路径
     * @param mb MapBean
     * @throws RuntimeException
     */
    public void setMapBeanByPath(String key, MapBean mb) throws RuntimeException {

        String[] keys = key.split("\\.");
        int len = keys.length;

        Map p_map = super.node.getIterator();

        TreeNode cnode = null;

        for (int i = 0; i < len - 1; i++) {
            int pos = keys[i].indexOf("[");
            if (pos != -1) {
                String rkey = keys[i].substring(0, pos);
                int rpos = Integer.parseInt(keys[i].substring(pos + 1, keys[i].length() - 1));
                Object lvalue = p_map.get(rkey);
                if (lvalue == null) {
                    lvalue = new ArrayList<TreeNode>();
                    p_map.put(rkey, lvalue);
                }

                if (rpos + 1 > ((List) lvalue).size()) {
                    cnode = new TreeNode();
                    p_map = cnode.getIterator();
                    ((List) lvalue).add(cnode);
                } else {
                    if (((List) lvalue).get(rpos) == null) {
                        cnode = new TreeNode();
                        p_map = cnode.getIterator();
                        ((List) lvalue).add(rpos, cnode);
                    } else {
                        p_map = ((TreeNode) ((List) lvalue).get(rpos)).getIterator();
                        logger.trace("Node 已经存在, 直接返回!");
                    }
                }

            } else {
                if (p_map.get(keys[i]) == null) {
                    p_map.put(keys[i], new TreeNode());
                }
                p_map = ((TreeNode) p_map.get(keys[i])).getIterator();
            }
        }

        int pos = keys[(len - 1)].indexOf("[");
        TreeNode setMN = mb.getNode();

        if (pos != -1) {
            String rkey = keys[(len - 1)].substring(0, pos);
            int rpos = Integer.parseInt(keys[(len - 1)].substring(pos + 1,
                    keys[(len - 1)].length() - 1));
            Object lvalue = p_map.get(rkey);

            if (lvalue instanceof TreeNode) { // 如果 lvalue 是MapNode , 则转为 List<TreeNode>

                Map<String, Object> target_map = ((TreeNode) lvalue).Iterator;
                Map<String, Object> setMap = setMN.Iterator;
                this.nodeMerger(target_map, setMap);

                List<TreeNode> transList = new ArrayList<TreeNode>();
                transList.add((TreeNode) lvalue);
                p_map.put(rkey, transList);

            } else { // lvalue 是已经存在的List
                if (lvalue == null) { // list 为空, 直接 add 值即可
                    lvalue = new ArrayList<TreeNode>();
                    p_map.put(rkey, lvalue);
                    ((List) lvalue).add(setMN);
                } else { // list 不为空
                    if (rpos + 1 > ((List) lvalue).size()) { // 超出list 的值, 有新的值, 直接 add 新值
                        // TODO
                        ((List) lvalue).add(setMN);
                    } else { // 合并重复的值

                        // ((List) lvalue).add(rpos, setMN);
                        Map<String, Object> target_map = ((TreeNode) (((List) lvalue).get(rpos))).Iterator;
                        Map<String, Object> setMap = setMN.Iterator;
                        this.nodeMerger(target_map, setMap);
                    }
                }
            }

        } else {
            if (p_map.get(keys[(len - 1)]) == null) { // 是否已经存在此MapNode 的key , 如果不存在 , 直接存放
                p_map.put(keys[(len - 1)], setMN);
            } else { // 如果已经存在此MapNode 的key ， 则对此key 中的内容进行追加 , 即将 setMN 中的内容追加到已经存在的 map中
                Map<String, Object> target_map = ((TreeNode) p_map.get(keys[(len - 1)])).Iterator; //

                Map<String, Object> setMap = setMN.Iterator;

                this.nodeMerger(target_map, setMap);

                logger.trace("对已有的MapBean节点进行了合并");
            }
        }

    }

    private void nodeMerger(Map<String, Object> target_map, Map<String, Object> setMap) {
        Iterator it = setMap.entrySet().iterator();

        while(it.hasNext()) {
            Map.Entry<String, TreeNode> en = (Map.Entry)it.next();
            if (!target_map.containsKey(en.getKey())) {
                target_map.put(en.getKey(), en.getValue());
            } else {
                Object targetObj = target_map.get(en.getKey());
                if (targetObj instanceof List) {
                    ((List)targetObj).add(en.getValue());
                } else {
                    List<TreeNode> targetList = new ArrayList();
                    targetList.add(en.getValue());
                    targetList.add((TreeNode)targetObj);
                    target_map.put(en.getKey(), targetList);
                }
            }
        }

    }

    private boolean isAdapterAttr(Map<String, String> attrMap, String... attrStrs) {
        boolean is_exist = true;
        if (attrMap.isEmpty()) {
            is_exist = false;
        } else {
            for(int i = 0; i < attrStrs.length; ++i) {
                String[] attrs = attrStrs[i].split("\\:");
                if (attrs.length != 2) {
                    is_exist = false;
                    break;
                }

                if (!attrMap.containsKey(attrs[0])) {
                    is_exist = false;
                    break;
                }

                String attr_value = (String)attrMap.get(attrs[0]);
                if (!attrs[1].equals(attr_value)) {
                    is_exist = false;
                    break;
                }
            }
        }

        return is_exist;
    }

    public List<MapBean> getMapBeanByAttr(String... attrStrs) {
        List<MapBean> list = new ArrayList();
        Map p_map = super.node.Iterator;
        Map nodeMap = new LinkedHashMap();
        this.iteratorMapBean(p_map, "", nodeMap);
        Iterator nodeMapIt = nodeMap.entrySet().iterator();

        while(nodeMapIt.hasNext()) {
            Map.Entry nodeMapE = (Map.Entry)nodeMapIt.next();
            TreeNode cnode = (TreeNode)nodeMapE.getValue();
            Map<String, String> attrMap = cnode.getNodeAttr();
            boolean is_exist = this.isAdapterAttr(attrMap, attrStrs);
            if (is_exist) {
                String[] keys = ((String)nodeMapE.getKey()).split("\\.");
                int len = keys.length;
                int pos = keys[len - 1].indexOf("[");
                String rkey = null;
                if (pos != -1) {
                    rkey = keys[len - 1].substring(0, pos);
                } else {
                    rkey = keys[len - 1];
                }

                list.add(new MapBean(rkey, cnode));
            }
        }

        return list;
    }

    private void iteratorMapBean(Map p_map, String path, Map nodeMap) {
        if (p_map == null) {
            ;
        }

        Map c_p_map = null;
        String c_p_path = null;
        Iterator it = p_map.entrySet().iterator();

        while(true) {
            while(it.hasNext()) {
                Map.Entry mapE = (Map.Entry)it.next();
                if (mapE.getValue() instanceof List) {
                    List list_node = (List)mapE.getValue();

                    for(int i = 0; i < list_node.size(); ++i) {
                        TreeNode cnode = (TreeNode)list_node.get(i);
                        c_p_map = cnode.getIterator();
                        if ("".equals(path)) {
                            c_p_path = (String)mapE.getKey() + "[0]";
                        } else {
                            c_p_path = path + "." + mapE.getKey() + "[" + i + "]";
                        }

                        nodeMap.put(c_p_path, cnode);
                        if (!c_p_map.isEmpty()) {
                            this.iteratorMapBean(c_p_map, c_p_path, nodeMap);
                        }
                    }
                } else {
                    TreeNode cnode = (TreeNode)mapE.getValue();
                    c_p_map = cnode.getIterator();
                    if ("".equals(path)) {
                        c_p_path = (String)mapE.getKey();
                    } else {
                        c_p_path = path + "." + mapE.getKey();
                    }

                    nodeMap.put(c_p_path, cnode);
                    if (!c_p_map.isEmpty()) {
                        this.iteratorMapBean(c_p_map, c_p_path, nodeMap);
                    }
                }
            }

            return;
        }
    }

    public int getListNum(String key) {
        return super.getListNum(key);
    }

    public TreeNode getNode() {
        return super.node;
    }

    public void removeNode(String key) {
        super.removeNode(key);
    }

    public String toString() {
        return this.toXML();
    }

}
